home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Libraries / VideoToolbox 97.08.16 / VideoToolboxSources / SetGestaltValue1.c < prev    next >
Encoding:
Text File  |  1997-07-09  |  8.4 KB  |  209 lines  |  [TEXT/CWIE]

  1. /*
  2. SetGestaltValue1.c
  3.  
  4. enum{gestaltPsychTable='Psyc'}                        // this can be whatever you want
  5.  
  6. error=SetGestaltValue1(gestaltPsychTable,table);    // install a table address
  7. error=SetGestaltValue1(gestaltPsychTable,NULL);        // replace the table address with NULL
  8.  
  9. error=Gestalt(gestaltPsychTable,&tablePtr);            // retrieve the table address
  10.  
  11. SetGestaltValue1.c provides an approximate equivalent for the
  12. SetGestaltValue() function provided in System 7.5 (see Apple's
  13. Gestalt.h), but only requires System 7 or better. SetGestaltValue1()
  14. allows you to install a new Gestalt selector or replace an existing selector
  15. installed by SetGestalt1. DON'T use SetGestaltValue1() to replace a
  16. pre-existing selector NOT installed by SetGestalt1 because its attempt
  17. to free the storage (upp and code) may fail.
  18.  
  19. The Macintosh Gestalt() function provides a way for many autonomous
  20. programs to share a global table. All the programs simply call Gestalt()
  21. with the same selector and Gestalt returns the table address. Any
  22. program calling Gestalt() to get the table address should check that
  23. error==0 and that table!=NULL before using the table. To set the
  24. selector and table address in Gestalt you can either use
  25. SetGestaltValue1 (this file), which works on all Mac Systems and
  26. architectures, or you can use Apple's routines.
  27.  
  28. Instead of using SetGestaltValue1 (this file), you could use Apple's
  29. routines. System 7.5 provides NewGestaltValue() and SetGestaltValue()
  30. (see Apple's Gestalt.h). PowerPC computers require System 7.5 or better,
  31. so your ppc code can safely assume the presence of those routines. If
  32. your program may be run on 68k computers running an earlier System, then
  33. your 68k code should link in Apple's GestaltValue.o library, which Apple
  34. supplies on their developer disks.
  35.  
  36. Invent your own selector name, e.g. gestaltPsychTable. By convention,
  37. the selector name should begin with "gestalt" and end with "Table". Its
  38. value is a four-character code, like 'Psyc'. Apple reserves all the
  39. lowercase-only codes for itself.
  40.  
  41. In order for the Gestalt selector routine to stick around, and not cause
  42. grief to Gestalt by disappearing when the application quits, we follow
  43. Apple's guidelines and install it in the System heap. Once installed
  44. it'll stay there until the machine is rebooted. You can't get rid of a
  45. selector once you've installed it, but you can call SetGestaltValue1()
  46. again, and assign the response NULL.
  47.  
  48. The selector function that we install into the System Heap is 68k code,
  49. because I know how to copy such routines, and have had no success doing
  50. so with ppc code. To have the 68k code available even when this file is
  51. compiled for ppc, without resorting to using resources, i.e. multiple files,
  52. i saved the machine code from a disassembly in a C array.
  53.  
  54. QUESTION:
  55. In thinking about the uses of this routine, it occurred to me that if an
  56. application creates a table in its own heap space and publishes the table's
  57. address via Gestalt, then it might happen that the application is
  58. abnormally terminated before it has a chance to NULL the table address
  59. published by Gestalt. The System would recover the application's memory,
  60. including the table, but the Gestalt value would persist, dangerously
  61. providing a pointer to memory that the System considers unassigned. So,
  62. how can we tell if a table pointer is valid?
  63.  
  64. ANSWER:
  65. Every running application has a unique process serial number (psn). An
  66. application that creates a table in its own heap space and publishes the
  67. table's address via Gestalt should store its psn in the table. Whenever
  68. we retrieve a table address via Gestalt we should check the psn field.
  69. If the table's psn field is not NULL, then we should make sure that that
  70. process is still running. At the moment, David Brainard and I are only
  71. worried about MEX files that all run as part of the MATLAB
  72. application, so it is enough for us to simply make sure that the stored
  73. psn matches our current psn. 
  74.  
  75. #include <Processes.h>
  76. ProcessSerialNumber psn;
  77. Boolean ours;
  78.  
  79. // when we make the table, mark it as our own
  80. error=GetCurrentProcess(&table->psn);
  81.  
  82. // when we access the table, make sure that it's ours
  83. error=GetCurrentProcess(&psn);
  84. error=SameProcess(&table->psn,&psn,&ours);  // Apple says this is the way to compare psns.
  85. if(!ours) table is invalid, 
  86.  
  87. HISTORY:
  88. 5/7/96 dgp wrote it.
  89. 5/9/96 dgp got it to work on ppc.
  90. 4/13/97    dgp eliminated the A6 stack frame from the 68K compiled code, since the was no
  91.             way for the Linker to fill in the zero field. I don't know if that matters,
  92.             but it is conceivable that we were clobbering memory. Now it should be safe.
  93. */
  94.  
  95. #include "VideoToolbox.h"
  96. //#include <Gestalt.h>
  97.  
  98. // modified from Gestalt.h because our routine is ALWAYS 68k code.
  99. #if GENERATINGCFM
  100.     #define New68kSelectorFunctionProc(userRoutine)        \
  101.             (SelectorFunctionUPP) NewRoutineDescriptor((ProcPtr)(userRoutine), uppSelectorFunctionProcInfo, kM68kISA)
  102. #else
  103.     #define New68kSelectorFunctionProc(userRoutine)        \
  104.             ((SelectorFunctionUPP) (userRoutine))
  105. #endif
  106.  
  107. #if (THINK_C || THINK_CPLUS || SYMANTEC_C)
  108.     #pragma options(!profile)
  109. #endif
  110. #if __MWERKS__ && __profile__
  111.     #pragma profile off
  112. #endif
  113.  
  114. // There's nothing special about these numbers. We hope that they won't coincide with
  115. // machine instructions used in the tiny MyGestaltValue program, immediately following.
  116. #define SELECTOR 0x12345678
  117. #define RESPONSE 0x87654321
  118.     
  119. // SetGestaltValue1 copies the compiled version (below) of this code to the
  120. // System heap and sets the copy's selector and response.
  121. pascal OSErr MyGestaltValue(OSType selector,long *response);    // private
  122. pascal OSErr MyGestaltValue(OSType selector,long *response)
  123. {
  124.     if(selector==SELECTOR){
  125.         *response=RESPONSE;
  126.         return 0;
  127.     }else return gestaltUnknownErr;
  128. }
  129.  
  130. /*
  131. MyGestaltValueCode is the 68k compiled code produced by Metrowerks CodeWarrior C
  132. for the MyGestaltValue routine above. This allows me to install a 68k
  133. code version even when this file is compiled for ppc. I've found it easy
  134. to copy, modify, and install a 68k routine, but haven't succeeded when I
  135. tried to do the same with a ppc routine, because I'm not quite sure what
  136. to do about the indirection through the TVector. I understand that transition
  137. vectors are documented in Apple's PowerPC Inside Mac books. Apple Developer
  138. Tech Support told me that all ppc routines are called indirectly via a TVector.
  139. */
  140. short myGestaltValueCode[]={
  141.     0x0CAF,0x1234,0x5678    // CMPI.L    #$12345678,$0008(A7)
  142.     ,0x0008           
  143.     ,0x6610                    // BNE.S     *+$0012
  144.     ,0x206F,0x0004            // MOVEA.L   $0004(A7),A0
  145.     ,0x20BC,0x8765,0x4321    // MOVE.L    #$87654321,(A0)
  146.     ,0x426F,0x000C            // CLR.W     $000C(A7)
  147.     ,0x6006                    // BRA.S     *+$0008
  148.     ,0x3F7C,0xEA52,0x000C    // MOVE.W    #$EA52,$000C(A7)
  149.     ,0x4E74,0x0008          // RTD       #$0008
  150.     ,0x8E4D,0x5947,0x4553    // DC.B      $80+$0E, 'MYGESTALTVALUE', $00
  151.     ,0x5441,0x4C54,0x5641 
  152.     ,0x4C55,0x4500,0x0000           
  153. };
  154.  
  155. OSErr SetGestaltValue1(OSType selector,long response)
  156. {
  157.     Ptr ptr;
  158.     OSErr error;
  159.     long value,version;
  160.     SelectorFunctionUPP upp,oldUpp;
  161.     THz heapZone;
  162.     long size;
  163.     unsigned short *wordPtr;
  164.     SelectorFunctionProcPtr functionPtr;
  165.     
  166.     Gestalt(gestaltSystemVersion,&version);
  167.     if(version<0x700)PrintfExit("%s %ld. Sorry. I need System 7 or better.\n",__FILE__,(long)__LINE__);
  168.     functionPtr=(void *)myGestaltValueCode;
  169.     size=sizeof(myGestaltValueCode);
  170.     // copy our function to System Heap
  171.     ptr=NewPtrSys(size);
  172.     if(ptr==NULL)PrintfExit("%s %ld. No space in System Heap.\n",__FILE__,(long)__LINE__);
  173.     BlockMove(functionPtr,ptr,size);
  174.     // Set the copy's selector and response.
  175.     wordPtr=(unsigned short *)ptr;
  176.     wordPtr[1]=selector>>16;
  177.     wordPtr[2]=selector&0xffff;
  178.     wordPtr[8]=response>>16;
  179.     wordPtr[9]=response&0xffff;
  180.     #if GENERATINGPOWERPC
  181.         MakeDataExecutable(ptr,size);
  182.     #else
  183.         FlushCodeCacheRange(ptr,size);
  184.     #endif
  185.     heapZone=GetZone();
  186.     SetZone(SystemZone());
  187.     upp=New68kSelectorFunctionProc(ptr);    // allocate UUP in System Heap
  188.     SetZone(heapZone);
  189.     // does our Gestalt selector already exist?
  190.     error=Gestalt(selector,&value);
  191.     if(!error){
  192.         // yes, replace it. (It may persist from an earlier run of MATLAB.)
  193.         error=ReplaceGestalt(selector,upp,&oldUpp);
  194.         if(error)PrintfExit("%s %ld. ReplaceGestalt error %ld.\n",__FILE__,(long)__LINE__,(long)error);
  195.         // free the old function's space in the System Heap
  196.         if(oldUpp!=NULL){
  197.             #if GENERATINGCFM
  198.                 DisposePtr((Ptr)oldUpp->routineRecords[0].procDescriptor);
  199.             #endif
  200.             DisposePtr((Ptr)oldUpp);
  201.         }
  202.     }else{
  203.         // no, install it.
  204.         error=NewGestalt(selector,upp);
  205.         if(error)PrintfExit("%s %ld. NewGestalt error %ld.\n",__FILE__,(long)__LINE__,(long)error);
  206.     }
  207.     return error;
  208. }
  209.